package ru.amse.jsynchro.net.server;

import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Semaphore;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import ru.amse.jsynchro.logging.ILogger;
import ru.amse.jsynchro.logging.LogFactory;

public class UserServer extends Server {
    private static int myThreadNumber = 0;
    private static UserServer server;
    private Map<String, Semaphore> userToSemaphore;
    private Properties config;
    
    private String usersFileName;
    private String configFileName = "./server_config";
    private String usersFolder;
    
    public static final String CONFIG_UPDATE = "update_config_period";
    public static final String USERS_FOLDER = "users_folder";
    public static final String USERS_ACCOUNT = "users_account_file";
    public static final String PORT = "port";
    
    private ILogger logger;
    
    public UserServer(ILogger logger) {
        super(logger);
        this.logger = logger;
        
        try {
            configure();
            userToSemaphore = createSemaphoreMap(usersFileName);
        } catch (ConfigFileException e1) {
            logger.exception(e1);
            setDefaultConfig();
        } catch (Exception e) {
            logger.exception(e);
            e.printStackTrace();
            throw new AssertionError("problems with users file");
        }
//        setDaemon(true);
    }
    
    private void setDefaultConfig() {
        setUsersFileName("./users.xml");
//        setConfigUpdatePeriod(10000);
        setUsersFolder("./users");
        setPort(12345);
    }

    public static void main(String[] args) {
        String logging = args[0];
        server = new UserServer(LogFactory.getServerLogger(true, logging));
        server.start();
    }
    
    public void run() {
        logger.info("server working");
//        UserServer connectionListener = new UserServer(logger) {
//            public void run() {
//                listenToClient();
//            }
//        };
//        connectionListener.start();
        listenToClient();
//        while (true) {
//            try {
//                Thread.sleep(updatePeriod);
//                if (connectionListener.configure()) {
//                    connectionListener.();
//                    sleep(1000);
//                    System.out.println(connectionListener.isAlive());
////                    connectionListener.start();
//                }
//            } catch (InterruptedException e) {
//                logger.exception(e);
//                throw new AssertionError(e.getMessage());
//            } catch (ConfigFileException e2) {
//                logger.exception(e2);
//            }
//        }
    }
    
    synchronized private boolean setUsersFileName(String fileName) {
        if (this.usersFileName != fileName) {
            this.usersFileName = fileName;
            return true;
        } else {
            return false;
        }
        
    }
    
    private boolean configure() throws ConfigFileException {
        config = new Properties();
        boolean result = false;
        try {
            config.load(new FileReader(configFileName));
        } catch (IOException e) {
            logger.exception(e);
        }
        try {
            if (setPort(Integer.parseInt(config.getProperty(PORT)))) {
                result = true;
            }
        } catch (NumberFormatException e) {
            throw new ConfigFileException("port is not a number");
        }
//        try {
//            if (setConfigUpdatePeriod(Integer.parseInt(config.getProperty(CONFIG_UPDATE)))) {
//                result = true;
//            }
//        } catch (NumberFormatException e) {
//            throw new ConfigFileException("update period is not a number");
//        }
        if (setUsersFileName(config.getProperty(USERS_ACCOUNT)) || 
        setUsersFolder(config.getProperty(USERS_FOLDER))) {
            
        }
        return result;
    }
    
//    private boolean setConfigUpdatePeriod(int updatePeriod) {
//        if (this.updatePeriod != updatePeriod) {
//            this.updatePeriod = updatePeriod;
//            return true;
//        } else {
//            return false;
//        }
//    }

    private boolean setUsersFolder(String usersFolder) {
        if (this.usersFolder != usersFolder) {
            this.usersFolder = usersFolder;
            return true;
        } else {
            return false;
        }
    }

    protected Thread getServerThread(Socket s) {
        return new UserServerThread(s, myThreadNumber++, userToSemaphore, usersFileName, logger);
    }
    
    private Map<String, Semaphore> createSemaphoreMap(String XMLFileName) throws ParserConfigurationException, SAXException, IOException {
        SAXParserFactory spf = SAXParserFactory.newInstance();
        SAXParser sparser = spf.newSAXParser();
        final Map<String, Semaphore> map = new HashMap<String, Semaphore>(); 
        DefaultHandler dh = new DefaultHandler() {
            public void startElement (String uri, String localName,
                String qName, Attributes attributes) throws SAXException {
                if (qName.equals("user")) {
                    map.put(attributes.getValue("name"), new Semaphore(1));
                }
            }
        };
        FileInputStream fis = new FileInputStream(XMLFileName);
        sparser.parse(fis, dh);
        return map;
    }

}
